package top.huxy.socketrequest.core;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;

import javax.websocket.*;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * @author aproz
 * @Date 2022/5/17
 */
@Slf4j
public abstract class SocketRequestServer implements InitializingBean {

    private Session session;
    private static String baseUrl;

    @Value("${server.port:8080}")
    String port;

    @Override
    public final void afterPropertiesSet() throws Exception {
        if (port != null) {
            baseUrl = "http://127.0.0.1:" + port;
        }
    }

    public static void setBaseUrl(String baseUrl) {
        SocketRequestServer.baseUrl = baseUrl;
    }

    @OnOpen
    public final void onOpen(Session session) {
        this.session = session;
        this.onSocketOpen(session);
    }


    @OnClose
    public final void onClose() {
        this.onSocketClose(session);
    }

    @OnError
    public final void onError(Throwable error) {
        log.error("onError", error);
        this.onSocketError(session, error);
    }


    @OnMessage
    public final void onMessage(String message) {
        SocketHttpRequest request;
        try {
            request = this.onSocketMessage(session, message);
        } catch (Exception e) {
            sendResponse(null, 400, null, "解析请求失败");
            return;
        }
        String requestId = request.getRequestId();

        String method = request.getMethod();
        Map<String, Object> data = request.getData();
        Map<String, String> header = request.getHeader();
        String url = request.getUrl();
        if (HttpMethod.GET.name().equalsIgnoreCase(method)) {
            HttpResponse response = HttpRequest.get(resolveUrl(url)).headerMap(header, true).execute();
            int responseCode = response.getStatus();
            Map<String, List<String>> responseHeaders = response.headers();
            String body = response.body();
            sendResponse(requestId, responseCode, responseHeaders, body);
        } else {
            HttpRequest httpRequest = HttpRequest.post(resolveUrl(url)).headerMap(header, true);
            if (data != null) {
                for (Map.Entry<String, Object> kv : data.entrySet()) {
                    String key = kv.getKey();
                    Object value = kv.getValue();
                    if (value instanceof String) {
                        httpRequest.form(key, value);
                    } else {
                        httpRequest.form(key, JSON.toJSONString(value));
                    }
                }
            }
            HttpResponse response = httpRequest.execute();
            int responseCode = response.getStatus();
            Map<String, List<String>> responseHeaders = response.headers();
            String body = response.body();
            sendResponse(requestId, responseCode, responseHeaders, body);
        }
    }


    private String resolveUrl(String url) {
        if (url.startsWith("/")) {
            return baseUrl + url;
        } else {
            return baseUrl + "/" + url;
        }
    }

    private void sendResponse(String requestId, int responseCode, Map<String, List<String>> responseHeaders, Object responseBody) {
        SocketHttpResponse response = new SocketHttpResponse(requestId, responseBody, responseHeaders, responseCode);
        this.beforeSendSocketResponse(session, response);
        try {
            session.getBasicRemote().sendText(JSON.toJSONString(response));
        } catch (IOException e) {
            this.onSendSocketResponseError(session, response);
        }
    }

    protected void onSocketError(Session session, Throwable error) {
    }

    protected void onSocketOpen(Session session) {
    }

    protected void onSocketClose(Session session) {
    }

    protected SocketHttpRequest onSocketMessage(Session session, String message) {
        return JSON.parseObject(message).to(SocketHttpRequest.class);
    }

    protected void onSendSocketResponseError(Session session, SocketHttpResponse response) {
    }

    protected void beforeSendSocketResponse(Session session, SocketHttpResponse response) {
    }
}
